package com.canton.service.impl;

import cn.hutool.core.util.StrUtil;
import com.canton.model.ontology.Statement;
import com.canton.service.KBQAService;
import com.hankcs.hanlp.dictionary.CoreSynonymDictionary;
import com.hankcs.hanlp.restful.HanLPClient;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

/**
 * @author: wujunchao
 * @date: 2021-12-04 20:23
 */
@Service
public class KBQAServiceImpl extends BaseService implements KBQAService {
    @Override
    public String getQuestion(String question) {
        String answer = "";
        int count = StrUtil.count(question, "？");
        if (count == 0){
            System.out.println("未检测到问题");
            answer = "未检测到问题，记得问题后要加中文问号标识喔~";
            return answer;
        }

        HanLPClient HanLP = new HanLPClient("https://www.hanlp.com/api", "NTcxQGJicy5oYW5scC5jb206dFJHcUFSNHpWRmNsWmw0bQ=="); // auth不填则匿名，zh中文，mul多语种
        Map<String, List> map = null;
        try {
            map = HanLP.parse(question);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List tokList = map.get("tok/coarse");
        List ctbList = map.get("pos/ctb");
        List nerList = map.get("ner/msra");

        System.out.println(tokList);
        System.out.println(ctbList);

        // 分词处理
        for(int i=0; i< ctbList.size(); i++){
            for(int j=0; j<  ((List) tokList.get(i)).size(); j++){
                if(((List) tokList.get(i)).get(j).equals("事件")){
                    ((List) tokList.get(i)).set(j,"相关事件");
                }
            }
            for(int j=0; j<  ((List) ctbList.get(i)).size(); j++){
                if(((List) ctbList.get(i)).get(j).equals("NN") &&
                        ((List) ctbList.get(i)).get(j+1).equals("NN")){
                    String NNNN = (String) ((List) tokList.get(i)).get(j) + ((List) tokList.get(i)).get(j+1);
//                    ((List) tokList.get(i)).set(j, NNNN);
//                    ((List) tokList.get(i)).set(j+1, 0);
                    ((List) ctbList.get(i)).set(j, "NN");
                    ((List) ctbList.get(i)).set(j+1, 0);
                }
            }
        }

        System.out.println(tokList);
        System.out.println(ctbList);

        if(count == 1){
            tokList = (List) tokList.get(0);
            ctbList = (List) ctbList.get(0);
            nerList = (List) nerList.get(0);
            System.out.println("单意图问题");
            if(nerList.size() == 1){ //只有一个实体时
                System.out.println("查实体");
                if(ctbList.indexOf("NN") == ctbList.lastIndexOf("NN")){
                    try{
                        int index = ctbList.indexOf("NN");
                        String relax = (String) tokList.get(index);
                        System.out.println("要查询的内容为:<"+ ((List) nerList.get(0)).get(0)+","+ relax +",?>");
                        answer = (String) findOneEntity((String) ((List) nerList.get(0)).get(0), relax).get("answer").get(0);
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("无法识别出要检索的关系");
                        answer = ("无法识别出要检索的关系");
                    }
                }else{
                    System.out.println("多跳链式查询");
                    List<String> subjectList = new ArrayList();
                    subjectList.add((String) ((List) nerList.get(0)).get(0));
                    for(int i =0; i < ctbList.size(); i++){
                        if (ctbList.get(i).equals("NN")){
                            for(int j =0; j < subjectList.size(); j++){
                                System.out.println(subjectList.get(j));
                                System.out.println((String) tokList.get(i));
                                map = findOneEntity(subjectList.get(j), (String) tokList.get(i));
                                if(map.get("objectList").size() == 0){
                                    answer = "未在知识库找到相关答案~ 请重新检索~";
                                    break;
                                }else{
                                    answer = answer.length()>0?answer + "，" + map.get("answer").get(0): (String) map.get("answer").get(0);
                                    subjectList.clear();
                                    subjectList.addAll(map.get("objectList"));
                                }
                            }
                        }
                    }
                }
            }else if(nerList.size() == 2){
                if (ctbList.contains("P") || ctbList.contains("VC")){
                    if (ctbList.contains("VV")){
                        String relax = "";
                        if(!(ctbList.indexOf("NN") == -1)){
                            relax = (String) tokList.get(ctbList.indexOf("NN"));
                        }else{
                            relax = "未知关系";
                        }
                        System.out.println("查两个实体的关系/属性交集");
                        System.out.println("要查询的内容为:<"+((List) nerList.get(0)).get(0)+","+relax+",?> 交集<"+
                                ((List) nerList.get(0)).get(0)+","+relax+",?>");
                        answer = ("要查询的内容为:<"+((List) nerList.get(0)).get(0)+","+relax+",?> 交集<"+
                                ((List) nerList.get(0)).get(0)+","+relax+",?>");
                    }else{
                        System.out.println("查两个实体的关系/属性");
                        System.out.println("要查询的内容为:<"+((List) nerList.get(0)).get(0)+",?,"+((List) nerList.get(0)).get(1)+">");
                        answer = ("要查询的内容为:<"+((List) nerList.get(0)).get(0)+",?,"+((List) nerList.get(0)).get(1)+">");
                    }
                }else if(ctbList.contains("CC")){
                    int index = ctbList.indexOf("NN");
                    String relax = (String) tokList.get(index);
                    if(relax.equals("关系")){
                        System.out.println("查两个实体的关系/属性");
                        System.out.println("要查询的内容为:<"+((List) nerList.get(0)).get(0)+",？,"+((List) nerList.get(1)).get(0)+">");
                        answer = ("要查询的内容为:<"+((List) nerList.get(0)).get(0)+",？,"+((List) nerList.get(1)).get(0)+">");
                    }else{
                        System.out.println("查两个实体的关系/属性交集");
                        System.out.println("要查询的内容为:<"+((List) nerList.get(0)).get(0)+","+relax+",?> 交集<"+((List) nerList.get(0)).get(1)+","+relax+",?>");
                        answer = ("要查询的内容为:<"+((List) nerList.get(0)).get(0)+","+relax+",?> 交集<"+((List) nerList.get(0)).get(1)+","+relax+",?>");
                    }
                }
            }
        }else{
            System.out.println("多意图问题");
            answer = ("多意图问题");
        }

        return answer.length()>0? answer:"小的知识有限，暂时无法解答该问题";
    }

    @Override
    public Map<String, List> findOneEntity(String subject, String relation) {
        System.out.println("subject:"+subject);
        System.out.println("relation:"+relation);
        String matchRelation = wordSimilarityRank(subject, relation); // 选出匹配最高的候选实体
        System.out.println("matchRelation:"+matchRelation);
        String sparqlStr =
                "SELECT DISTINCT ?subject ?predicate ?object "
                        + "WHERE {"
                        + " {?subject ?predicate ?object."
                        +" FILTER (REGEX(STR(?subject), '"+subject+"'))."
                        +" FILTER (REGEX(STR(?predicate), '"+matchRelation+"'))."
                        +" FILTER (ISIRI(?subject))."
                        +" FILTER (ISIRI(?object)).}"
                        + "}";
        Collection<Statement> statements = getOntologyResolver().query(sparqlStr);
        System.out.println(statements);
        String answer = "";
        List<String> objectList = new ArrayList<>();
        if(statements.size() == 1){
            Iterator<Statement> iter = statements.iterator();
            String String_subject = "";
            String String_predicate = "";
            String String_object = "";
            while (iter.hasNext()) {
                Statement statement = iter.next();
                String_subject = statement.getSubject();
                String_predicate = statement.getPredicate();
                String_object = statement.getObject();
                objectList.add(statement.getObject());
            }
            answer = String_subject + "的" +  String_predicate + "是" + String_object;

        }else if(statements.size() > 1){
            Iterator<Statement> iter = statements.iterator();
            String String_subject = "";
            String String_predicate = "";
            String String_object = "";
            while (iter.hasNext()) {
                Statement statement = iter.next();
                String_subject = String_subject.length()>0?String_subject:statement.getSubject();
                String_predicate = String_predicate.length()>0?String_predicate:statement.getPredicate();
                String_object = String_object.length()>0?String_object + "、" + statement.getObject():statement.getObject();
                objectList.add(statement.getObject());
            }
            answer = String_subject + "的" +  String_predicate + "有" + String_object;
        } else{
            answer = "未在知识库找到相关答案~ 请重新检索~";
        }
        Map<String, List> map = new HashMap();
        map.put("answer", Collections.singletonList(answer));
        map.put("objectList", objectList);
        return map;
    }

    @Override
    public String wordSimilarityRank(String entity, String relaxtion) {
        String sparqlStr =
                "SELECT DISTINCT ?subject ?predicate ?object "
                        + "WHERE {"
                        + " {?subject ?predicate ?object."
                        + " FILTER (REGEX(STR(?subject), '#" + entity + "$'))."
                        + " FILTER (!REGEX(STR(?predicate), 'rdf'))."
                        + " FILTER (!REGEX(STR(?predicate), 'Recall'))."
                        + " FILTER (ISIRI(?subject))."
                        + " FILTER (ISIRI(?object)).}"
                        + "}";
        Collection<Statement> statements = getOntologyResolver().query(sparqlStr);
        List<String> predicateList = new ArrayList<String>();
        Iterator<Statement> iter = statements.iterator();
        while (iter.hasNext()) {
            Statement statement = iter.next();
            if (!predicateList.contains(statement.getPredicate())){
                predicateList.add(statement.getPredicate());
            }
        }
        System.out.println("predicateList:" + predicateList);
        String matchPre = "";
        if(predicateList.contains(relaxtion)){
            matchPre = relaxtion;
        }else{
            int preNum = 0;
            for (int i = 0; i < predicateList.size(); i++) {
                if(CoreSynonymDictionary.similarity(relaxtion,predicateList.get(i)) > preNum){
                    matchPre = predicateList.get(i);
                    preNum = (int) CoreSynonymDictionary.similarity(relaxtion,predicateList.get(i));
                }
            }
            System.out.println("matchPre:" + matchPre);
            System.out.println("preNum:" + preNum);
        }
        return matchPre;
    }
}
